#include"Camera.h"


Camera::Camera()
{
   // Initialize variables...
   mPos = D3DXVECTOR3(0.0f, 0.0f, 0.0f);
   mView = D3DXVECTOR3(0.0f, 0.0f, 0.0f);
   mUp = D3DXVECTOR3(0.0f, 0.0f, 0.0f);
   mStrafe = D3DXVECTOR3(0.0f, 0.0f, 0.0f);
   distance=-300.0f;
   height=100.0;
   createCamera(0.1f, 10000.0f);

   currentRotationAngle = 0.0f;
}


void Camera::SetCamera(float x, float y, float z,
                        float xv, float yv, float zv,
                        float xu, float yu, float zu)
{
   // Here we set the camera to the values sent in to us.  This is mostly used to set up a
   // default position.
   mPos = D3DXVECTOR3(x, y, z);
   mView = D3DXVECTOR3(xv, yv, zv);
   mUp = D3DXVECTOR3(xu, yu, zu);
}

void Camera::UpdateCamera()
{
   // Move the camera on the X and Z axis.
	pointCamera();
}

void Camera::GetDirection(D3DXVECTOR3 &Direction)
{
   // The look direction is the view (where we are looking) minus the position (where we are).
   Direction = mView - mPos;
}


void Camera::MoveCamera(float speed)
{
   // Moving the camera requires a little more then adding 1 to the z or subracting 1.
   // First we need to get the direction at which we are looking.
   D3DXVECTOR3 Direction;

   // Get the direction and store it in the object Direction.
   GetDirection(Direction);
}


void Camera::StrafeCam(float speed)
{
   CalculateStrafe();                           // Calculate the strafe direction.
}

void Camera::CalculateStrafe()
{
   D3DXVECTOR3 Direction;
   D3DXVECTOR3 Cross;
   float magnitude = 0.0;

   // Strafing is just like moving the camera forward and backward.  First we will get the
   // direction we are looking.
   GetDirection(Direction);

   // Save our strafe (cross product) values in the mStrafe object.
   mStrafe = Cross;
}


void Camera::RotateCamera(float AngleDir, D3DXVECTOR3 Speed)
{
   D3DXVECTOR3 newDir;
   D3DXVECTOR3 LookDirection;
   float CosineAngle, SineAngle = 0.0;

   // First we will need to calculate the cos and sine of our angle.  I created two macros to
   // do this in the Camera.h header file called GET_COS and GET_SINE.  To use the macros
   // we just send in the variable we ant to store the results and the angle we need to
   // calculate.
	GET_COS(CosineAngle, AngleDir);
    GET_SINE(SineAngle, AngleDir);

	// Next get the look direction (where we are looking) just like in the move camera function.
    GetDirection(LookDirection);

	// Calculate the new X position.
	newDir.x = (CosineAngle + (1 - CosineAngle) * Speed.x) * LookDirection.x;
	newDir.x += ((1 - CosineAngle) * Speed.x * Speed.y - Speed.z * SineAngle)* LookDirection.y;
	newDir.x += ((1 - CosineAngle) * Speed.x * Speed.z + Speed.y * SineAngle) * LookDirection.z;

	// Calculate the new Y position.
	newDir.y = ((1 - CosineAngle) * Speed.x * Speed.y + Speed.z * SineAngle) * LookDirection.x;
	newDir.y += (CosineAngle + (1 - CosineAngle) * Speed.y) * LookDirection.y;
	newDir.y += ((1 - CosineAngle) * Speed.y * Speed.z - Speed.x * SineAngle) * LookDirection.z;

	// Calculate the new Z position.
	newDir.z = ((1 - CosineAngle) * Speed.x * Speed.z - Speed.y * SineAngle) * LookDirection.x;
	newDir.z += ((1 - CosineAngle) * Speed.y * Speed.z + Speed.x * SineAngle) * LookDirection.y;
	newDir.z += (CosineAngle + (1 - CosineAngle) * Speed.z) * LookDirection.z;


	// Last we add the new rotations to the old view to correctly rotate the camera.
    mView = mPos + newDir;
}

void Camera::RotateByMouse(int mousePosX, int mousePosY, int midX, int midY)
{
	float yDirection = 0.0f;         // Direction angle.
	float yRotation = 0.0f;          // Rotation angle.

	// If the mouseX and mouseY are at the middle of the screen then we can't rotate the view.
	if((mousePosX == midX) && (mousePosY == midY))
      return;

	// Next we get the direction of each axis.  We divide by 1000 to get a smaller value back.
	yDirection = (float)((midX - mousePosX)) / 1000.0f;		
	yRotation = (float)((midY - mousePosY)) / 1000.0f;		

	// We use curentRotX to help use keep the camera from rotating too far in either direction.
	currentRotationAngle -= yRotation;  

	// Stop the camera from going to high...
	if(currentRotationAngle > 1.5f)
    {
		 currentRotationAngle = 1.5f;
         return;
    }

	// Stop the camera from going to low...
	if(currentRotationAngle < -1.5f)
	{
         currentRotationAngle = -1.5f;
         return;
    }

   // Next we get the axis which is a perpendicular vector of the view direction and up values.
   // We use the cross product of that to get the axis then we normalize it.
   Vector3D Axis;

   // Rotate the camera.
   RotateCamera(yRotation, D3DXVECTOR3(Axis.x, Axis.y, Axis.z));
   RotateCamera(-yDirection, D3DXVECTOR3(0, 1, 0));
}

void Camera::CrossProduct(D3DXVECTOR3 m_direction, D3DXVECTOR3 m_tDir )
{
	mUp.x=(m_direction.y*m_tDir.z-m_direction.z*m_tDir.y);
	mUp.y=(m_direction.z*m_tDir.x-m_direction.x*m_tDir.z);
	mUp.z=(m_direction.x*m_tDir.y-m_direction.y*m_tDir.x);
}

void Camera::createCamera(float nearClip, float farClip)
{
	D3DXMATRIX						matProj;
	//Here we specify the field of view, aspect ration and near and far clipping planes.
    D3DXMatrixPerspectiveFovLH(&matProj, D3DX_PI/4, 640/480, nearClip, farClip);
    dxMgr.getDevice()->SetTransform(D3DTS_PROJECTION, &matProj);
}

void Camera::rotUp(float addnum)
{
	if(height<300)
	{
		height+=addnum;
	}
}

void Camera::rotDown(float subnum)
{
	if(height > 0)
	{
		height-=subnum;
	}
}

void Camera::pointCamera()
{
	D3DXMATRIX	matView;
	D3DXVECTOR3 cameraPosition =mPos+mView*distance;			// the position of the camera
	D3DXVECTOR3 cameraLook = mPos;				// where the camera is pointing
	D3DXVECTOR3 cUp = mUp;
	cameraPosition.y=height;
	cameraLook.y=mPos.y+50;

	D3DXMatrixLookAtLH(&matView, &cameraPosition,		//Camera Position
                                 &cameraLook,			//Look At Position
                                 &cUp);		//Up Direction

	dxMgr.getDevice()->SetTransform(D3DTS_VIEW, &matView);
}


